package com.foreverwin.jzymes.common.service.impl;

import com.foreverwin.jzymes.common.constant.Constants;
import com.foreverwin.jzymes.common.domain.CarrierBind;
import com.foreverwin.jzymes.common.domain.NcData;
import com.foreverwin.jzymes.common.domain.SfcBatchPassLog;
import com.foreverwin.jzymes.common.enums.DispositionEnum;
import com.foreverwin.jzymes.common.mapper.*;
import com.foreverwin.jzymes.common.service.*;
import com.foreverwin.jzymes.common.util.BOHandleUtil;
import com.foreverwin.jzymes.common.util.CommonMethods;
import com.foreverwin.jzymes.framework.exception.BusinessException;
import com.foreverwin.jzymes.framework.util.BeanUtil;
import com.foreverwin.jzymes.framework.util.I18nUtil;
import com.foreverwin.jzymes.production.sfc.domain.SFC;
import com.foreverwin.jzymes.production.sfc.enums.ProcedureEnum;
import com.foreverwin.jzymes.production.sfc.mapper.SFCAdviceMapper;
import com.foreverwin.jzymes.production.sfc.mapper.SFCMapper;
import com.sap.me.extension.Services;
import com.sap.me.frame.transitionutils.Exceptions;
import com.sap.me.numbering.GenerateNextNumberRequest;
import com.sap.me.numbering.GenerateNextNumberResponse;
import com.sap.me.numbering.NextNumberTypeEnum;
import com.sap.me.numbering.NumberingServiceInterface;
import com.sap.me.production.ScrapDeleteServiceInterface;
import com.sap.me.production.ScrapSfcRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
public class CommonServiceImpl implements ICommonService {

    @Autowired
    ISiteAdviceService siteAdviceService;
    @Autowired
    IItemAdviceService itemAdviceService;
    @Autowired
    ICarrierBindAdviceService carrierBindAdviceService;
    @Autowired
    ISfcBatchPassLogAdviceService sfcBatchPassLogAdviceService;
    @Autowired
    ISfcBatchPassLogService sfcBatchPassLogService;
    @Autowired
    IActivityLogAdviceService activityLogAdviceService;
    @Autowired
    INCDataAdviceService ncDataAdviceService;
    @Autowired
    IResourceAdviceService resourceAdviceService;
    @Autowired
    IResourceTypeAdviceService resourceTypeAdviceService;
    @Autowired
    ISfcStepAdviceService sfcStepAdviceService;
    @Autowired
    IRouterStepAdviceService routerStepAdviceService;
    @Autowired
    IItemGroupAdviceService itemGroupAdviceService;
    @Autowired
    INCCodeAdviceService incCodeAdviceService;
    @Autowired
    INCCodeAdviceService ncCodeAdviceService;
    @Autowired
    ISystemRuleAdviceService systemRuleAdviceService;
    @Autowired
    ICustomFieldsAdviceService customFieldsAdviceService;
    @Autowired
    SFCMapper sfcMapper;
    @Autowired
    SFCAdviceMapper sfcAdviceMapper;
    @Autowired
    CarrierBindMapper carrierBindMapper;
    @Autowired
    SfcBatchPassLogAdviceMapper sfcBatchPassLogAdviceMapper;
    @Autowired
    NcDataAdviceMapper ncDataAdviceMapper;
    @Autowired
    NcDataMapper ncDataMapper;
    @Autowired
    OperationAdviceMapper operationAdviceMapper;

    /**
     * 查询研磨工作中工令
     * 按时间排序取第一笔记录
     *
     * @param site
     * @param itemBo
     * @return
     */
    public List<SFC> findGrindSfcOnWork( String site, String itemBo ){
        /**查询研磨工作中的工令*/
        return findSfcOnWork( site, itemBo, ProcedureEnum.GRIND.name() );
    }

    /**
     * 查询CNC工作中工令
     * 按时间排序取第一笔记录
     *
     * @param site
     * @param itemBo
     * @return
     */
    public List<SFC> findCNCSfcOnWork( String site, String itemBo ){
        /**查询研磨工作中的工令*/
        return findSfcOnWork( site, itemBo, ProcedureEnum.CNC.name() );
    }

    /**
     * 查询制程工作中的工令
     * 按时间排序取第一笔记录
     *
     * @param site
     * @param itemBo
     * @param procedure
     * @return
     */
    public List<SFC> findSfcOnWork( String site, String itemBo, String procedure ){
        /**检查站点是否存在*/
        siteAdviceService.existSite( site );
        /**检查物料是否存在*/
        itemAdviceService.existItem( itemBo );

        /**查询工作中的工令*/
        String procedureBo = BOHandleUtil.buildFieldGroupHandle( site, procedure );
        List<SFC> sfcList =  sfcAdviceMapper.selectSFCListOnWork( site, procedureBo, itemBo );
        if( sfcList == null || sfcList.size() == 0 ){
            throw BusinessException.build("common.sfcOnWorkNotFoundByItem", new String[]{ procedure,itemBo } );
        }
        return sfcList;
    }

    /**
     * 研磨报废更新工令已下达数量、制程报废数量，保存不良数量
     *
     * @param site
     * @param itemBo
     * @param resource
     * @param ncCode
     * @param scrapQty
     * @param updateDate
     */
    public void updateGrindSfcForScrap( String site, String itemBo, String resource, String ncCode, Long scrapQty, Date updateDate ){
        Long scrapQtyBak = scrapQty;
        List<SFC> sfcList = findGrindSfcOnWork( site, itemBo );

        for( SFC sfc : sfcList ){
            Long sfcReleasedQty = sfc.getReleasedQty() == null ? 0 : sfc.getReleasedQty();
            //Long sfcScrapQty = sfc.getScrapQty() == null ? 0 : sfc.getScrapQty();
            Long ncQty = 0L;

            if( sfc.getActStartTime() == null ){
                sfc.setActStartTime( updateDate );
                sfc.setStatusBo( "StatusBO:"+ site +",403" );
            }

            /**修改工令字段*/
            if( scrapQtyBak >= ( sfc.getSfcQty() - sfcReleasedQty ) ){
                sfc.setReleasedQty( sfc.getSfcQty() );
                //sfc.setScrapQty( sfcScrapQty + ( sfc.getSfcQty() - sfcReleasedQty ) );
                ncQty = sfc.getSfcQty() - sfcReleasedQty;
                scrapQtyBak = scrapQtyBak - ncQty;
                /*if( sfc.getActEndTime() == null ){
                    sfc.setActEndTime( updateDate );
                    sfc.setStatusBo( "StatusBO:"+ site +",405" );
                }*/
            }else {
                sfc.setReleasedQty( sfcReleasedQty + scrapQtyBak );
                //sfc.setScrapQty( sfcScrapQty + scrapQtyBak );
                ncQty = scrapQtyBak;
                scrapQtyBak = 0L;
            }

            sfc.setUpdatedDateTime( updateDate );
            sfc.setUpdateUserBo( CommonMethods.getUserBo() );
            sfcMapper.updateSFC( sfc );

            /**保存不良数据*/
            ncDataAdviceService.saveNcData( sfc, null, null, resource, null, ncCode, ncQty, DispositionEnum.SCRAP, updateDate );

            if( scrapQtyBak == 0 ){
                break;
            }
        }

        /**工作中工令数量不满足待处理数量*/
        if( scrapQtyBak > 0 || sfcList.size() == 0 ){
            throw BusinessException.build("production.sfc.sfcOnWorkNotMeetNeedQty", new Object[]{ scrapQty } );
        }

    }


    /**
     * 研磨产出更新工令
     *
     * @param site
     * @param itemBo
     * @param needQty
     * @param resource
     * @param updateDate
     */
    public void updateGrindSfcForPass( String site, String itemBo, Long needQty, String resource, Date updateDate ){
        Long needQtybak = needQty;

        List<SFC> sfcList = findGrindSfcOnWork( site, itemBo );

        /**检查工作中的工令并更新已下达数量和良品产出数量，保存过站记录*/
        for( SFC sfc : sfcList ){
            Long sfcReleasedQty = sfc.getReleasedQty() == null ? 0 : sfc.getReleasedQty();
            //Long sfcOkQty = sfc.getOkQty() == null ? 0 : sfc.getOkQty();
            Long passQty = 0L;

            if( sfc.getActStartTime() == null ){
                sfc.setActStartTime( updateDate );
                sfc.setStatusBo( "StatusBO:"+ site +",403" );
            }

            /**修改工令字段*/
            if( needQtybak >= ( sfc.getSfcQty() - sfcReleasedQty ) ){
                sfc.setReleasedQty( sfc.getSfcQty() );
                //sfc.setOkQty( sfcOkQty + ( sfc.getSfcQty() - sfcReleasedQty ) );
                passQty = sfc.getSfcQty() - sfcReleasedQty;
                needQtybak = needQtybak - passQty;
                /*if( sfc.getActEndTime() == null ){
                    sfc.setActEndTime( updateDate );
                    sfc.setStatusBo( "StatusBO:"+ site +",405" );
                }*/
            }else {
                sfc.setReleasedQty( sfcReleasedQty + needQtybak );
                //sfc.setOkQty( sfcOkQty + needQtybak );
                passQty = needQtybak;
                needQtybak = 0L;
            }

            sfc.setUpdatedDateTime( updateDate );
            sfc.setUpdateUserBo( CommonMethods.getUserBo() );
            sfcMapper.updateSFC( sfc );

            /**保存过站记录*/
            activityLogAdviceService.saveActivityLog( site, sfc.getSfc(), itemBo, null, null, resource, null, passQty, updateDate );

            if( needQtybak == 0 ){
                break;
            }
        }

        /**工作中工令数量不满足待处理数量*/
        if( needQtybak > 0 || sfcList.size() == 0 ){
            throw BusinessException.build("production.sfc.sfcOnWorkNotMeetNeedQty", new Object[]{ needQty } );
        }
    }

    /**
     * 本体设备过站
     *
     * @param site
     * @param carrier
     * @param resource
     * @param passDate
     * @return
     */
    public Map<String,String> sfcPassByCarrier( String site, String carrier, String resource, Date passDate ){

        /**查询工序*/
        String operation = resourceAdviceService.findOperationByResource( site, resource );
        return sfcPassByCarrier( site, carrier, resource, operation, passDate );
    }

    /**
     * 本体工序过站
     *
     * @param site
     * @param carrier
     * @param operation
     * @param passDate
     * @return
     */
    public Map<String,String> sfcPassByCarrierOnOperation( String site, String carrier, String operation, Date passDate ){

        /**查询设备*/
        String resource = findOperationDefaultResource( site, operation );
        return sfcPassByCarrier( site, carrier, resource, operation, passDate );
    }

    /**
     * 本体过站
     *
     * @param site
     * @param carrier
     * @param resource
     * @param operation
     * @param passDate
     * @return
     */
    public Map<String,String> sfcPassByCarrier( String site, String carrier, String resource, String operation, Date passDate ){
        Map<String,String> sfcMap = new HashMap<>();

        /**检查本体绑定*/
        List<CarrierBind> carrierBindList = carrierBindAdviceService.existCarrierBindonBind( site, carrier );

        for( CarrierBind carrierBind : carrierBindList ){

            /**检查本体自绑定后在工序已经过站,则不再过站*/
            if( checkCarrierPassOnOperation( carrierBind, operation ) ){
                return sfcMap;
            }

            /**检查待过站工序是否是本体当前所在工序*/
            //Assert.isTrue( carrierBind.getNextOperation() == null || carrierBind.getNextOperation().equals( operation ), I18nUtil.getI18nText( "common.carrierNotPassOnOperation", new String[]{ carrier, carrierBind.getNextOperation(), operation } ) );

            /**工令数量过站*/
            List<String> sfcs = new ArrayList<>();
            NcData ncData = ncDataAdviceService.findItemOpenNcDataFromDate( carrierBind.getSite(), carrierBind.getCarrier(), carrierBind.getItemBo() );

            if( ncData != null ){
                /**检查NC是否要在全检拦截报废*/
                if( StringUtils.isBlank( ncData.getDisposition() ) ){
                    String futureOperation = ncCodeAdviceService.findNCValidOper( ncData.getSite(), ncData.getNcCode() );
                    if( StringUtils.isNotBlank( futureOperation ) && !ncData.getOperation().equals( futureOperation ) ){
                        ncData.setOperation( futureOperation );
                        ncDataMapper.updateNcData( ncData );
                    }
                }
                /**检查前面工序是否存在未处置的不合格*/
                List<String> prevOperationList = findSfcPrevOperationList( carrierBind.getSite(), carrierBind.getItemBo(), operation );
                if( prevOperationList.contains( ncData.getOperation() ) || operation.equals( ncData.getOperation() ) ){
                    throw BusinessException.build( I18nUtil.getI18nText("production.nc.carrierItemNCExistNotDispose", new String[]{ ncData.getCarrier(), ncData.getItemBo(), ncData.getOperation(), ncData.getNcCode() } ) );
                }

                //SFC sfc = sfcMapper.selectSFCById( BOHandleUtil.buildSFCHandle( ncData.getSite(), ncData.getSfc() ) );
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( ncData.getSite(), ncData.getSfc(), ncData.getItemBo(), resource, ncData.getNcQty(), passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( ncData.getSite(), ncData.getSfc(), ncData.getItemBo(), ncData.getCarrier(), ncData.getDateCode(), resource, ncData.getNcQty(), passDate );
            }else{
                sfcs = sfcPassByQty( carrierBind.getSite(), carrierBind.getItemBo(), carrierBind.getCarrier(), null, resource, operation, 1L, passDate );
            }

            /**设置本体下一待过站工序*/
            String nextOperation = findSfcNextOperation( site, carrierBind.getItemBo(), operation );
            carrierBind.setNextOperation( nextOperation );
            carrierBindMapper.updateCarrierBind( carrierBind );

            if( sfcs.size() > 0 ){
                sfcMap.put( carrierBind.getItemBo(), sfcs.get(0) );
            }
        }
        return sfcMap;
    }

    /**
     * 工令数量过站
     *
     * @param site
     * @param resource
     * @param passQty
     * @param passDate
     */
    public void sfcPassByQty( String site, String resource, Long passQty, Date passDate ){

        /**根据机种查询物料*/
        String itemGroup = itemGroupAdviceService.findItemGroupBySite( site );
        List<Map<String,Object>> items = itemGroupAdviceService.findItemGroupMember( site, itemGroup );

        /**查询工序*/
        String operation = resourceAdviceService.findOperationByResource( site, resource );

        /**根据物料、工序查询可用sfc*/
        for( Map<String,Object> itemMap : items ){
            sfcPassByQty( site, (String) itemMap.get( "ITEM_BO" ), null, null, resource, operation, passQty, passDate );
        }
    }

    /**
     * 工令数量过站
     *
     * @param site
     * @param itemBo
     * @param carrier
     * @param dateCode
     * @param resource
     * @param passQty
     * @param passDate
     * @return
     */
    public List<String> sfcPassByQty( String site, String itemBo, String carrier, String dateCode, String resource, String operation, Long passQty, Date passDate ){
        List<String> sfcs = new ArrayList<>();

        Long needQty = passQty;
        //List<SFC> sfcList = findCNCSfcOnWork( site, itemBo );
        List<Map<String,Object>> sfcList = findAvailSfcList( site, itemBo, operation, needQty );
        //for( SFC sfc : sfcList ){
        for( Map<String,Object> sfcMap : sfcList ){

            /**查询工令在工序排队中数量*/
            /*Long qtyInQueue = findSfcQtyInQueueOnOperation( site, sfc.getSfc(), operation );
            if( qtyInQueue <= 0 ){
                continue;
            }*/
            String sfc = (String) sfcMap.get( "SFC" );
            Long qtyInQueue = (Long) sfcMap.get( "QTY" );

            sfcs.add( sfc );

            /**工令数量过站*/
            if( needQty > qtyInQueue ){
                needQty = needQty - qtyInQueue;
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc, itemBo, resource, qtyInQueue, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc, itemBo, carrier, dateCode, resource, qtyInQueue, passDate );
                continue;
            }else{
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc, itemBo, resource, needQty, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc, itemBo, carrier, dateCode, resource, needQty, passDate );
                needQty = 0L;
                break;
            }
        }

        if( needQty > 0 ){
            /**保存工令批次过站数量*/
            //sfcBatchPassLogAdviceService.saveSfcBatchPass( site, null, itemBo, resource, needQty, passDate );
            /**保存本体过站记录*/
            //activityLogAdviceService.saveActivityLog( site, null, itemBo, carrier, dateCode, resource, needQty, passDate );
            throw BusinessException.build("production.sfc.sfcOnWorkNotMeetNeedQty", new Object[]{ passQty } );
            //passQtyAutoRecover( site, itemBo, carrier, dateCode, resource, operation, needQty, sfcs );
        }

        return sfcs;
    }

    public void passQtyAutoRecover( String site, String itemBo, String carrier, String dateCode, String resource, String operation, Long passQty, List<String> sfcs ){
        List<SFC> sfcList = findCNCSfcOnWork( site, itemBo );
        String prevOperation = findSfcPrevOperation( site, itemBo, operation );
        String prevResource = findOperationDefaultResource( site, prevOperation );

        for( SFC sfc : sfcList ) {

            /**查询前一工序过站数量*/
            Long prevPassQty = null;
            if( StringUtils.isBlank( prevOperation ) ){
                prevPassQty = sfc.getSfcQty();
            }else{
                prevPassQty = sfcBatchPassLogAdviceMapper.selectSfcPassQtyOnOperation( site, sfc.getSfc(), prevOperation );
                Long ngQty = ncDataAdviceMapper.selectSfcNGQtyOnOperation( site, sfc.getSfc(), prevOperation );
                ngQty = ngQty == null ? 0L : ngQty;
                prevPassQty = prevPassQty + ngQty;
            }
            prevPassQty = prevPassQty == null ? 0L : prevPassQty;
            if( sfc.getSfcQty().equals( prevPassQty )  ){
                continue;
            }

            if( !sfcs.contains( sfc.getSfc() ) ){
                sfcs.add( sfc.getSfc() );
            }

            Date passDate = new Date();
            if( passQty > sfc.getSfcQty() - prevPassQty ){
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc.getSfc(), itemBo, prevResource, sfc.getSfcQty() - prevPassQty, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc.getSfc(), itemBo, carrier, dateCode, prevResource, sfc.getSfcQty() - prevPassQty, passDate );
                passDate = new Date();
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc.getSfc(), itemBo, resource, sfc.getSfcQty() - prevPassQty, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc.getSfc(), itemBo, carrier, dateCode, resource, sfc.getSfcQty() - prevPassQty, passDate );

                passQty = passQty - ( sfc.getSfcQty() - prevPassQty );
            }else{
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc.getSfc(), itemBo, prevResource, passQty, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc.getSfc(), itemBo, carrier, dateCode, prevResource, passQty, passDate );
                passDate = new Date();
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfc.getSfc(), itemBo, resource, passQty, passDate );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( site, sfc.getSfc(), itemBo, carrier, dateCode, resource, passQty, passDate );

                passQty = 0l;
                break;
            }
        }

        if( passQty > 0 ){
            throw BusinessException.build("production.sfc.sfcOnWorkNotMeetNeedQty", new Object[]{ passQty } );
        }
    }

    /**
     * 获取工序默认资源
     * @param site
     * @param operation
     * @return
     */
    public String findOperationDefaultResource( String site, String operation ){
        Map<String,Object> operationMap = operationAdviceMapper.selectDefaultResource( site, operation );
        String resource = null;
        if( operationMap != null && operationMap.get( "RESOURCE_BO" ) != null ){
            resource = BOHandleUtil.splitResourceHandle( (String)operationMap.get( "RESOURCE_BO" ) )[1];
        }
        return resource;
    }

    /**
     * 查询工令在工序排队中数量
     *
     * @param site
     * @param sfc
     * @param operation
     * @return
     */
    public Long findSfcQtyInQueueOnOperation( String site, String sfc, String operation ){

        SFC _sfc = sfcMapper.selectSFCById( BOHandleUtil.buildSFCHandle( site, sfc ) );
        //SFC _sfc = sfcAdviceMapper.selectSFCForUpdate( BOHandleUtil.buildSFCHandle( site, sfc ) );
        String prevOperation = findSfcPrevOperation( site, _sfc.getItemBo(), operation );

        /**查询前一工序过站数量*/
        Long prevPassQty = null;
        if( StringUtils.isBlank( prevOperation ) ){
            prevPassQty = _sfc.getSfcQty();
        }else{
            prevPassQty = sfcBatchPassLogAdviceMapper.selectSfcPassQtyOnOperation( site, sfc, prevOperation );
        }
        prevPassQty = prevPassQty == null ? 0L : prevPassQty;

        /**查询当前工序过站数量*/
        Long passQty = sfcBatchPassLogAdviceMapper.selectSfcPassQtyOnOperation( site, sfc, operation );
        passQty = passQty == null ? 0L : passQty;

        /**查询当前工序处置方式非合格数量（报废数量、返工数量、未处置数量）*/
        Long ngQty = ncDataAdviceMapper.selectSfcNGQtyOnOperation( site, sfc, operation );
        ngQty = ngQty == null ? 0L : ngQty;

        return prevPassQty - passQty - ngQty;
    }

    /**
     * 检查本体在工序是否已过站
     *
     * @param carrierBind
     * @param passOperation
     * @return
     */
    public boolean checkCarrierPassOnOperation( CarrierBind carrierBind, String passOperation ){
        boolean passed = false;
        /**本体绑定时工序为空*/
        if( StringUtils.isBlank( carrierBind.getNextOperation() ) ){
            return passed;
        }
        /**查询工序前面工序*/
        List<String> prevOperationList = findSfcPrevOperationList( carrierBind.getSite(), carrierBind.getItemBo(), carrierBind.getNextOperation() );
        if( prevOperationList.contains( passOperation ) ){
            passed = true;
        }
        return passed;
    }

    /**
     * 查询下一个工序
     *
     * @param site
     * @param itemBo
     * @param operation
     * @return
     */
    public String findSfcNextOperation( String site, String itemBo, String operation ){
        List<String> nextOperationList = findSfcNextOperationList( site, itemBo, operation );
        return nextOperationList.get( 0 );
    }

    /**
     * 查询后面工序列表
     *
     * @param site
     * @param itemBo
     * @param operation
     * @return
     */
    public List<String> findSfcNextOperationList( String site, String itemBo, String operation ){
        /**查询工令使用的工艺路线*/
        Map<String,Object > itemMap = itemAdviceService.existItem( itemBo );
        String routerBo = (String) itemMap.get( "ROUTER_BO" );
        /**查询后续工序列表*/
        List<String> nextOperationList = routerStepAdviceService.findNextOperationList( site, routerBo, operation );
        return nextOperationList;
    }

    /**
     * 查询前面工序列表
     *
     * @param site
     * @param itemBo
     * @param operation
     * @return
     */
    public List<String> findSfcPrevOperationList( String site, String itemBo, String operation ){
        /**查询工令使用的工艺路线*/
        Map<String,Object > itemMap = itemAdviceService.existItem( itemBo );
        String routerBo = (String) itemMap.get( "ROUTER_BO" );
        /**查询前面工序列表*/
        List<String> prevOperationList = routerStepAdviceService.findPrevOperationList( site, routerBo, operation );
        return prevOperationList;
    }

    /**
     * 查询前一工序
     *
     * @param site
     * @param itemBo
     * @param operation
     * @return
     */
    public String findSfcPrevOperation( String site, String itemBo, String operation ){
        List<String> prevOperationList = findSfcPrevOperationList( site, itemBo, operation );
        if( prevOperationList == null || prevOperationList.size() == 0 ){
            return null;
        }
        return prevOperationList.get( prevOperationList.size() - 1 );
    }

    /**
     * 保存不良数据录入
     *
     * @param ncData
     * @param rework
     */
    public void saveNcData( NcData ncData, boolean rework ){
        saveNcData( ncData, ncData.getResrce(), ncData.getOperation(), rework );
    }

    /**
     * 保存不良数据录入
     *
     * @param ncData
     * @param resource
     * @param operation
     * @param rework
     */
    public void saveNcData( NcData ncData, String resource, String operation,  boolean rework ){
        Long needQty = ncData.getNcQty();
        //List<SFC> sfcList = findCNCSfcOnWork( ncData.getSite(), ncData.getItemBo() );
        List<Map<String,Object>> sfcList = findAvailSfcList( ncData.getSite(), ncData.getItemBo(), operation, needQty );
        //for( SFC sfc : sfcList ){
        for( Map<String,Object> sfcMap : sfcList ){

            /**查询工令在工序排队中数量*/
            /*Long qtyInQueue = findSfcQtyInQueueOnOperation( ncData.getSite(), sfc.getSfc(), operation );
            if( qtyInQueue <= 0 ){
                continue;
            }*/

            String sfc = (String) sfcMap.get( "SFC" );
            Long qtyInQueue = (Long) sfcMap.get( "QTY" );

            long pice = 0L;
            if( needQty > qtyInQueue ){
                pice = qtyInQueue;
                needQty = needQty - qtyInQueue;
            }else{
                pice = needQty;
                needQty = 0L;
            }

            /**保存不良数据*/
            NcData _ncData = new NcData();
            BeanUtil.copyBeanProp( _ncData, ncData );
            _ncData.setSfc( sfc );
            _ncData.setNcQty( pice );
            _ncData.setHandle( BOHandleUtil.buildNCDataHandle() );
            ncData = _ncData;
            ncDataMapper.insertNcData( _ncData );


            if( DispositionEnum.SCRAP.getValue().equals( _ncData.getDisposition() ) ){
                if( resourceAdviceService.isCNC1( _ncData.getSite(), resource ) ){
                    /**扣减工令批次过站数量*/
                    reduceOpenSfcBatchPassLogQty( _ncData.getSite(), _ncData.getItemBo(), _ncData.getResrce(), _ncData.getNcQty() );
                }
                /**报废MES工令数量*/
                scrapSfcQty( _ncData.getSite(), _ncData.getSfc(), resource, _ncData.getNcQty(), _ncData.getCreatedDateTime() );
            }

            if( !DispositionEnum.SCRAP.getValue().equals( _ncData.getDisposition() ) && !rework ){
                /**保存工令批次过站数量*/
                sfcBatchPassLogAdviceService.saveSfcBatchPass( ncData.getSite(), sfc, ncData.getItemBo(), resource, _ncData.getNcQty(), _ncData.getCreatedDateTime() );
                /**保存本体过站记录*/
                activityLogAdviceService.saveActivityLog( ncData.getSite(), sfc, ncData.getItemBo(), _ncData.getCarrier(), _ncData.getDateCode(), resource, _ncData.getNcQty(), _ncData.getCreatedDateTime() );
            }

            if( needQty == 0 ){
                break;
            }
        }

        /**工令数量不足*/
        if( needQty > 0 ){
            /*NcData _ncData = new NcData();
            BeanUtil.copyBeanProp( _ncData, ncData );
            _ncData.setNcQty( needQty );
            _ncData.setHandle( BOHandleUtil.buildNCDataHandle( _ncData.getSite(), _ncData.getSfc(), _ncData.getResrce(), _ncData.getNcCode(), _ncData.getCreatedDateTime() ) );
            ncDataMapper.insertNcData( _ncData );*/
            throw BusinessException.build("production.sfc.sfcOnWorkNotMeetNeedQty", new Object[]{ ncData.getNcQty() } );
        }

        /**料件和本体解绑*/
        if( DispositionEnum.SCRAP.getValue().equals( ncData.getDisposition() ) && StringUtils.isNotBlank( ncData.getCarrier() ) ){
            carrierBindAdviceService.carrierUnBind( ncData.getSite(),ncData.getCarrier(), ncData.getItemBo(), ncData.getCreatedDateTime() );
        }
    }

    /**
     * 报废Mes工令数量
     *
     * @param site
     * @param sfc
     * @param resource
     * @param scrapQty
     * @param scrapDate
     */
    public void scrapSfcQty( String site, String sfc, String resource, Long scrapQty, Date scrapDate ){
        try{
            ScrapDeleteServiceInterface scrapDeleteService = Services.getService( "com.sap.me.production", "ScrapDeleteService", site );
            ScrapSfcRequest scrapSfcRequest = new ScrapSfcRequest();
            scrapSfcRequest.setSfcRef( BOHandleUtil.buildSFCHandle( site, sfc ) );
            scrapSfcRequest.setLogResourceRef( BOHandleUtil.buildResourceHandle( site, resource ) );
            scrapSfcRequest.setLogOperationRef( resourceAdviceService.findOperationBoByResource( site, resource ) );
            scrapSfcRequest.setQuantity( BigDecimal.valueOf( scrapQty ) );
            scrapDeleteService.scrapSfc( scrapSfcRequest );
        }catch (com.sap.me.frame.domain.BusinessException e) {
            throw BusinessException.build( e.getMessage() );
        }
    }

    /**
     * 生成编号
     *
     * @param site
     * @return
     */
    public String generateOrderNo( String site, String orderNumberRule ){
        String orderNo = null;
        try {
            NumberingServiceInterface numberingService = Services.getService( "com.sap.me.numbering", "NumberingService", site );
            GenerateNextNumberRequest nextNumberRequest = new GenerateNextNumberRequest();
            nextNumberRequest.setNextNumberType( NextNumberTypeEnum.SFCSERIALIZATION );
            nextNumberRequest.setNumberOfValues( BigDecimal.ONE );
            nextNumberRequest.setItemRef( BOHandleUtil.buildItemHandleAllRev( site, orderNumberRule ) );

            GenerateNextNumberResponse nextNumberResponse = numberingService.generateNextNumber( nextNumberRequest );
            orderNo = nextNumberResponse.getId().get( 0 );
        } catch (com.sap.me.frame.domain.BusinessException e) {
            throw BusinessException.build( Exceptions.convert( e ).toString() );
        }
        if( StringUtils.isBlank( orderNo ) ){
            throw BusinessException.build( "common.orderNumberGenerateFail", new String[]{ orderNumberRule } );
        }
        return orderNo;
    }

    public List<Map<String,Object>> findAvailSfcList( String site, String itemBo, String operation, Long needQty ){
        List<Map<String,Object>> availSfcList = new ArrayList<>();
        List<SFC> sfcList = findCNCSfcOnWork( site, itemBo );
        for( SFC sfc : sfcList ) {
            Long qty = 0L;

            /**工令加锁*/
            Logger logger = LoggerFactory.getLogger( CommonServiceImpl.class );
            logger.info( "itemBo " + itemBo + " sfc " + sfc.getSfc() + " 开始加锁" );
            sfcAdviceMapper.selectSFCForUpdate( sfc.getHandle() );
            logger.info( "itemBo " + itemBo + " sfc " + sfc.getSfc() + " 结束加锁" );

            /**查询工令在工序排队中数量*/
            Long qtyInQueue = findSfcQtyInQueueOnOperation( site, sfc.getSfc(), operation );
            if (qtyInQueue <= 0) {
                continue;
            }

            if( needQty > qtyInQueue ){
                needQty = needQty - qtyInQueue;
                qty = qtyInQueue;
            }else{
                qty = needQty;
                needQty = 0L;
            }

            Map<String,Object> sfcMap = new HashMap<>();
            sfcMap.put( "SFC", sfc.getSfc() );
            sfcMap.put( "QTY", qty );
            availSfcList.add( sfcMap );

            if( needQty == 0 ){
                break;
            }
         }
        return availSfcList;
    }

    public void reduceOpenSfcBatchPassLogQty( String site, String itemBo, String resource, Long qty ){

        Logger logger = LoggerFactory.getLogger( CommonServiceImpl.class );
        logger.info( "enter reduceOpenSfcBatchPassLogQty " + itemBo );
        resource = resourceAdviceService.findTranship( site, resource );
        SfcBatchPassLog sfcBatchPassLog = sfcBatchPassLogAdviceService.findOpenSfcBatchPassLogListByOperation( site, itemBo, resource );
        if( sfcBatchPassLog != null ){
            logger.info( "enter saveSfcBatchPass " + itemBo );
            sfcBatchPassLogAdviceService.saveSfcBatchPass( site, sfcBatchPassLog.getSfc(), itemBo, sfcBatchPassLog.getResrce(), -1 * qty, new Date() );
            logger.info( "leave saveSfcBatchPass " + itemBo );
        }else{
            logger.info( "enter findAvailSfcList " + itemBo );
            String operation = resourceAdviceService.findOperationByResource( site, resource );
            List<Map<String,Object>> availSfcList = findAvailSfcList( site, itemBo, operation, qty );
            for( Map<String,Object> sfcMap : availSfcList ){
                sfcBatchPassLogAdviceService.saveSfcBatchPass( site, (String)sfcMap.get("SFC"), itemBo, resource, operation, -1 * qty, new Date() );
            }
            logger.info( "leave findAvailSfcList " + itemBo );
        }
        logger.info( "leave reduceOpenSfcBatchPassLogQty " + itemBo );
    }

    /**
     * 查找工令物料
     *
     * @param site
     * @param itemBo
     * @return
     */
    public String findSfcItemByItem( String site, String itemBo ){
        Map<String,Object> itemMap = itemAdviceService.existItem( itemBo );
        if( itemMap.get( "ITEM_TYPE" ).equals( "P" ) ){
            String item = BOHandleUtil.splitItemHandle( itemBo )[1];
            String _itemBo = customFieldsAdviceService.findCustomFieldHandle( site, Constants.ITEM_CUSTOM_FIELD_RAW_ITEM, item );
            if( _itemBo != null ){
                itemBo = _itemBo;
            }
        }
        String itemLabel = customFieldsAdviceService.existCustomValue( itemBo, Constants.ITEM_CUSTOM_FIELD_ITEM_LABEL );
        String itemGroup = itemGroupAdviceService.findItemGroupBySite( site );

        List<Map<String,Object>> itemTreeList = new ArrayList<>();
        findItemTree( site, itemGroup, itemTreeList, false, null );
        for( Map<String,Object> _itemMap : itemTreeList ) {
            String _itemLabel = customFieldsAdviceService.existCustomValue((String) _itemMap.get("HANDLE"), Constants.ITEM_CUSTOM_FIELD_ITEM_LABEL);
            if( itemLabel.equals( _itemLabel ) ){
                return (String) _itemMap.get("HANDLE");
            }
        }
        return itemBo;
    }

    /**
     * 查询站点有效机种
     *
     * @param site
     * @param itemGroup
     * @return
     */
    /*public List<Map<String,Object>> findItemGroupMember( String site, String itemGroup ){
        List<String> itemGroupList = customFieldsAdviceService.findCustomFieldHandleList( site, Constants.ITEM_GROUP_CUSTOM_FIELD_REFER_ITEM_GROUP, itemGroup );
        itemGroupList.add( BOHandleUtil.buildItemGroupHandle( site, itemGroup ) );
        List<Map<String,Object>> itemMemberList = new ArrayList<>();
        for( String _itemGroup : itemGroupList ){
            _itemGroup = BOHandleUtil.splitItemGroupHandle( _itemGroup )[1];
            List<Map<String,Object>> memberList =  itemGroupAdviceService.findItemGroupMember( site, _itemGroup );
            itemMemberList.addAll( memberList );
        }
        return itemMemberList;
    }*/

    /**
     * 查询物料所在机种
     *
     * @param site
     * @param itemBo
     * @return
     */
    public String findItemGroupByItem( String site, String itemBo ){
        String item = BOHandleUtil.splitItemHandle( itemBo )[1];
        String _itemBo = customFieldsAdviceService.findCustomFieldHandle( site, Constants.ITEM_CUSTOM_FIELD_RAW_ITEM, item );
        if( _itemBo != null ){
            return findItemGroupByItem( site, _itemBo );
        }
        String itemGroup = itemGroupAdviceService.findItemGroupByItem( itemBo );
        if( itemGroup == null ){
            throw BusinessException.build( "common.itemNotMatchValidItemGroup", new String[]{ item } );
        }
        return itemGroup;
    }

    public void findItemTree( String site, String itemGroup, List<Map<String,Object>> itemTreeList, boolean refer, String itemType ){
        List<Map<String,Object>> itemMemberList =  itemGroupAdviceService.findItemGroupMember( site, itemGroup );
        List<Map<String,Object>> itemList = new ArrayList<>();
        for( Map<String,Object> itemMemberMap : itemMemberList ) {
            String itemBo = (String) itemMemberMap.get("ITEM_BO");
            Map<String, Object> itemMap = itemAdviceService.existItem(itemBo);
            itemList.add( itemMap );
        }
        findItemTree( site, itemGroup, itemList, itemTreeList, itemType );

        if( refer ){
            List<String> itemGroupList = customFieldsAdviceService.findCustomFieldHandleList( site, Constants.ITEM_GROUP_CUSTOM_FIELD_REFER_ITEM_GROUP, itemGroup );
            for( String itemGroupHandle : itemGroupList ){
                String _itemGroup = BOHandleUtil.splitItemGroupHandle( itemGroupHandle )[1];
                findItemTree( site, _itemGroup, itemTreeList, refer, itemType );
            }
        }
    }

    public void findItemTree( String site, String itemGroup, List<Map<String, Object>> itemList, List<Map<String,Object>> itemTreeList, String itemType ){
        List<Map<String,Object>> _itemList = new ArrayList<>();
        for( Map<String,Object> itemMap : itemList ){
            String itemBo = (String) itemMap.get("HANDLE");

            if( StringUtils.isBlank( itemType ) || itemType.equals( itemMap.get("ITEM_TYPE") ) ){
                itemMap.put( "ITEM_GROUP", itemGroup );
                itemTreeList.add( itemMap );
            }

            String rawItem = customFieldsAdviceService.findCustomValue( itemBo, Constants.ITEM_CUSTOM_FIELD_RAW_ITEM );
            if( StringUtils.isNotBlank( rawItem ) ) {
                Map<String, Object> rawItemMap = itemAdviceService.existItem(BOHandleUtil.buildItemHandleAllRev(site, rawItem));
                _itemList.add( rawItemMap );
            }
        }
        if( _itemList.size() > 0 ){
            findItemTree( site, itemGroup, _itemList, itemTreeList, itemType );
        }
    }
}
